package com.cupd.mbank.controller.h5;

import com.alibaba.fastjson.JSONObject;
import com.cupd.app.bean.IBusinessContext;
import com.cupd.app.service.SDKCommonService;
import com.cupd.commons.model.AppConstants;
import com.cupd.commons.model.Properties;
import com.cupd.commons.model.SessConsts;
import com.cupd.commons.util.MyX509TrustManager;
import com.cupd.commons.util.StringUtil;
import com.cupd.mbank.net.http.BaseMsgHttp;
import org.apache.commons.lang.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ConnectException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.HashMap;
import java.util.Map;
@RestController
public class OcrSDK extends SDKCommonService {

    private final Logger logger = LoggerFactory.getLogger(this.getClass());

    protected static final String CHARSET = "UTF-8";
    protected static final String WX_APP_ID = Properties.getString("WX_APP_ID").trim();//appid
    protected static final String WX_SECRET = Properties.getString("WX_SECRET").trim();//secret
    protected static final String WX_URL_H5FACE = Properties.getString("WX_URL_H5FACE").trim();//后台上送身份信息  进行人脸认证
    protected static final String WX_URL_IDCARD_API = Properties.getString("WX_URL_IDCARD_API").trim();//身份证识别api
    protected static final String WX_URL_STARTH5FACEOCR = Properties.getString("URL_STARTH5FACEOCR").trim();//启动人脸摄像头接口
    protected static final String WX_URL_GETOCRRESULT_FACE = Properties.getString("WX_URL_GETOCRRESULT_FACE").trim();//刷脸结果查询

    /**
     * OCR扫描身份证  H5版
     * @param request
     * @return
     */
    @RequestMapping("/IdCardH5.do")
    @ResponseBody
    public JSONObject IdCardH5(HttpServletRequest request) {
        /**
         * 1,获取请求参数并校验
         */
        IBusinessContext busiCtx = busiCtxFactory.createBusiContext(request);
        JSONObject reqJson = busiCtx.getInitParam();
        JSONObject resultJson = new JSONObject();
        Result result = checkParams(reqJson, "BACKCROP","FRONTCROP");
        if (!result.FLAG) {
            return result.RST;
        }
        String idBackImage = reqJson.getString("BACKCROP").replaceAll("\r|\n", "");
        String idFrontImage = reqJson.getString("FRONTCROP").replaceAll("\r|\n", "");

        try {
            /**
             * 2,准备获取sign的参数
             */
            String url = "/srv/getOpLogSeq.do";
            JSONObject resJson = BaseMsgHttp.sendTransMsg(url, reqJson);
            logger.info("IdCardH5.do resJson"+resJson);
            String user_id = (String) request.getSession().getAttribute(SessConsts.CUSTNO);
            String orderNo = StringUtil.todayStr("yyyyMMddhhmmss") + resJson.getString("transFlowNo");
            logger.info("app_id-secret-userId:" + WX_APP_ID + "\n" + WX_SECRET + "\n" + user_id);//如果user_id为空,表示登陆超时

            /**
             * 3,获取sign并判断是否成功
             */
            Map<String, Object> signMap = getApiTicket(WX_APP_ID, WX_SECRET, user_id);
            if (!signMap.get(AppConstants.RET_CODE).equals(AppConstants.RET_AAAAAA)) {
                logger.info("IdCardH5.do failed");
                responseFailure(resJson, "sign请求失败了:" + signMap.get("errmsg"));
                return resJson;
            }

            /**
             * 4,上送身份证正面BASE64到腾讯云服务器
             */
            JSONObject tencentJson = new JSONObject();
            tencentJson.put("cardType", "0");//0:正面
            tencentJson.put("version", version);
            tencentJson.put("orderNo", orderNo);
            tencentJson.put("webankAppId", WX_APP_ID);
            tencentJson.put("idcardStr", idFrontImage);
            tencentJson.put("sign", signMap.get("sign"));
            tencentJson.put("nonce", signMap.get("random"));
            JSONObject idFrontRes = BaseMsgHttp.sendTransMsg(WX_URL_IDCARD_API, tencentJson);
            logger.info("idFrontImage send result"+idFrontRes);

            /**
             * 5,上传身份证反面BASE64到腾讯云服务器
             */
            if ("0".equals(idFrontRes.get("code"))) {
                tencentJson.put("cardType", "1");//1:反面
                tencentJson.put("idcardStr", idBackImage);
                JSONObject idBackRes = BaseMsgHttp.sendTransMsg(WX_URL_IDCARD_API, tencentJson);
                if ("0".equals(idBackRes.get("code"))) {
                    responseSuccess(resultJson, "成功获取身份证信息");
                } else {
                    responseFailure(resultJson,(String)idBackRes.get("msg"));
                }
            } else {
                responseFailure(resultJson,(String)idFrontRes.get("msg"));
            }
        } catch (Exception e) {
            logger.info("IdCardH5Exception", e);
            responseFailure(resultJson,"接口获取身份证内容解析错误");
        }

        return resultJson;
    }

    /**
     * 人脸OCR  H5版
     *
     * @param request
     * @return
     */
    @RequestMapping("/ocrFace/startFaceOCR.do")
    @ResponseBody
    public void startFaceOCR(HttpServletRequest request, HttpServletResponse response) {
        try {
            /**
             * 1,获取请求参数并校验
             */
            IBusinessContext busiCtx = busiCtxFactory.createBusiContext(request);
            JSONObject reqJson = busiCtx.getInitParam();
            logger.info("req startFaceOCR param--->"+reqJson);
            String name = reqJson.getString("CARDNAME").trim();
            String idNo = reqJson.getString("CARDIDNO").trim();
            String user_id = (String) request.getSession().getAttribute(SessConsts.CUSTNO);

            /**
             * 2,准备获取sign的参数
             */
            String url = "/srv/getOpLogSeq.do";
            JSONObject resJson = BaseMsgHttp.sendTransMsg(url, reqJson);
            logger.info("IdCardH5.do resJson"+resJson);
            String orderNo = StringUtil.todayStr("yyyyMMddhhmmss") + resJson.getString("transFlowNo");
            logger.info("app_id-secret-userId:" + WX_APP_ID + "\n" + WX_SECRET + "\n" + user_id+"\n"+orderNo);//如果user_id为空,表示登陆超时

            /**
             * 3,发送身份信息到腾讯服务器
             */
            String h5faceId = null;
            JSONObject resMsg = sendUserMsg(user_id, name, idNo, orderNo);
            logger.info("upload Tencent server result"+resMsg);
            if (AppConstants.STATUS_OK.equals(resMsg.getString(AppConstants.STATUS))) {
                h5faceId = resMsg.getString("h5faceId");
            }

            /**
             * 4,获取sign并判断是否成功
             */
            String nonce = RandomStringUtils.randomAlphanumeric(32);
            Map<String, Object> signMap = getApiTicketFaceId(WX_APP_ID, WX_SECRET, user_id,orderNo,h5faceId,nonce);
            logger.info("IdCardH5.do failed"+signMap);

            /**
             * 5,重定向到req_url,启动H5刷脸
             */
            String domain = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort()+request.getContextPath();
            logger.info("ocrFace callback url--->"+domain);
            String callBackUrl = URLEncoder.encode(domain + "/ocrFace/faceRecognitionCallback.do", CHARSET);//回调url
            Map<String, Object> params = new HashMap<>();
            params.put("nonce", nonce);
            params.put("userId", user_id);
            params.put("version", version);
            params.put("url", callBackUrl);
            params.put("orderNo", "orderNo");
            params.put("h5faceId", h5faceId);
            params.put("webankAppId", WX_APP_ID);
            params.put("sign", signMap.get("sign"));
            String redirectUrl = valueToUrl(WX_URL_STARTH5FACEOCR, params);
            logger.info("redirectUrl--->"+redirectUrl);
            response.sendRedirect(redirectUrl);
        } catch (IOException e) {
            logger.info("startFaceOCRException--->",e);
        }
    }

    /**
     * H5人脸回调
     * 人脸验证完成后的回调接口 获取orderNo，h5faceId，signature
     */
    /**
     * 人脸OCRH5页面完成回调
     * @param request
     * @return
     */
    @RequestMapping("/faceRecognitionCallback.do")
    @ResponseBody
    public JSONObject faceRecognitionCallback(HttpServletRequest request) {
        logger.info("WeChat callBack URL--->" + request.getRequestURL());
        /**
         * 1,获取人脸验证结果
         */
        IBusinessContext busiCtx = busiCtxFactory.createBusiContext(request);
        JSONObject reqJson = busiCtx.getInitParam();
        String code = reqJson.getString("code");
        String orderNo = null;
        String h5faceId = null;
        String signature = null;
        if ("0".equals(code)) {
            //人脸验证成功
            orderNo = reqJson.getString("orderNo");
            h5faceId = reqJson.getString("h5faceId");
            signature = reqJson.getString("signature");
            logger.info("H5ocrFace success Result param---> orderNo=" + orderNo + "&h5faceId=" + h5faceId + "&signature=" + signature);
        } else {
            // 人脸验证失败
            orderNo = reqJson.getString("orderNo");
            h5faceId = reqJson.getString("h5faceId");
            signature = reqJson.getString("signature");
            logger.info("H5ocrFace failed Result paramcode=" + code +" orderNo=" + orderNo + "h5faceId=" + h5faceId + "signature=" + signature);
        }

        // 2.人脸结果信息查询retult
        JSONObject resMsg = new JSONObject();
        JSONObject faceRetult = getFaceInfo(WX_APP_ID,WX_SECRET,orderNo);
        if(!AppConstants.STATUS_OK.equals(faceRetult.get(AppConstants.STATUS))){
            resMsg.put("addressURI","OCR/open_face_fail.do");
            return resMsg;
        }

        resMsg.put("addressURI","OCR/open_face_success.do");
        return resMsg;
    }

    /**
     * 发送身份信息到腾讯服务器
     *
     * @param userId
     * @param name
     * @param idNo
     * @return
     */
    public JSONObject sendUserMsg(String userId, String name, String idNo, String orderNo) {
        JSONObject resultJson = new JSONObject();

        /**
         * 2,生成签名
         */
        Map<String, Object> signMap = getApiTicket(WX_APP_ID, WX_SECRET, userId);
        logger.info("sendUserMsg signMap--->" + signMap);

        /**
         * 3,上送身份信息到腾讯服务器
         */
        JSONObject reqTencent = new JSONObject();
        reqTencent.put("name", name);
        reqTencent.put("idNo", idNo);
        reqTencent.put("userId", userId);
        reqTencent.put("orderNo", orderNo);
        reqTencent.put("version", version);
        reqTencent.put("webankAppId", WX_APP_ID);
        reqTencent.put("sign", signMap.get("sign"));
        JSONObject resParam = BaseMsgHttp.sendTransMsg(WX_URL_H5FACE, reqTencent);
        logger.info("sendUserMsg send result--->" + resParam);

        /**
         * 4,处理上送结果
         */
        if ("0".equals(resParam.getString("code"))) {
            JSONObject faceJson = JSONObject.parseObject(resParam.getString("result"));
            String h5faceId = faceJson.getString("h5faceId");
            resultJson.put("h5faceId", h5faceId);
            responseSuccess(resultJson, resParam.getString("msg"));
        } else {
            logger.info("sendUserMsg send failed");
            responseFailure(resultJson, resParam.getString("msg"));
        }
        return resultJson;
    }

    public JSONObject getFaceInfo(String appid,String secret,String orderNo) {
        JSONObject resMsg = new JSONObject();
        String random = RandomStringUtils.randomAlphanumeric(32);
        String sign = "这里需要获取";
        logger.info("获取facesign" + sign);

        /**
         * 拼接url
         */
        Map<String, Object> params = new HashMap<>();
        params.put("sign", sign);
        params.put("app_id", appid);
        params.put("nonce", random);
        params.put("get_file", "1");
        params.put("version", version);
        params.put("order_no", orderNo);
        String url = valueToUrl(WX_URL_GETOCRRESULT_FACE,params);
        String recParam = httpRequest(url, "GET");
        logger.info("查询接口https://idasc.webank.com/api/server/sync返回信息" + recParam);
        JSONObject resJson = null;
        try{
            resJson = JSONObject.parseObject(recParam);
        }catch (Exception e){
            logger.info("内容解析为json异常" + e);
            responseFailure(resMsg, "str->json转换异常");
            return resMsg;
        }
        String msg = (String) resJson.get("msg");
        String returnCode = (String) resJson.get("code");
        String photo = null;
        String video = null;
        if ("0".equals(returnCode)) {
            // 查询返回成功
            String order_no = (String) resJson.get("order_no");
            JSONObject resultJson = (JSONObject) resJson.get("result");
            photo = (String) resultJson.get("photo");
            video = (String) resultJson.get("video");
        } else {
            // 查询人脸结果返回失败。
            logger.info("查询人脸结果返回失败,code="+ returnCode +"失败提示：" + msg);
            //查询人脸返回失败时,尝试获取人脸图像photo
            try {
                JSONObject resultJson = (JSONObject) resJson.get("result");
                photo = String.valueOf(resultJson.get("photo"));
                video = String.valueOf(resultJson.get("video"));
                //查询到photo\video信息为空时,返回到人脸验证失败页面
                if("null".equalsIgnoreCase(photo) || "".equals(photo) || null == photo){
                    logger.info("人脸识别失败，不能获取到photo,尝试获取video");
                    if("null".equalsIgnoreCase(video) || "".equals(video) || null == video){
                        logger.info("获取video失败!");
                        responseFailure(resMsg, msg);
                        return resMsg;
                    }
                }
            } catch (Exception e) {
                logger.info("尝试获取人脸图像异常，应是腾讯云返回的信息中没有result节点");
                //1、查询人脸识别结果返回失败
                //2、查询失败下，尝试拉取人脸图片失败。
                responseFailure(resMsg, msg);
                return resMsg;
            }
        }
        responseSuccess(resMsg, "成功");
        resMsg.put("PHOTO",photo);
        resMsg.put("VIDEO",video);
        resMsg.put("FACECODE",returnCode);//人脸验证结果code=0:成功。其他表示人脸失败
        return resMsg;
    }

    /**
     * 给指定url拼接参数reqParam  ps：http://url?a=1&b=2
     * @param reqUrl
     * @param reqParam
     * @return
     */
    public String valueToUrl(String reqUrl, Map<String, Object> reqParam){
        StringBuffer sb = new StringBuffer();
        if (reqParam != null && reqParam.size() > 0) {
            for (Map.Entry<String, Object> entry : reqParam.entrySet()) {
                sb.append(entry.getKey());
                sb.append("=");
                sb.append(entry.getValue());
                sb.append("&");
            }
        }
        URL url = null;
        try {
            if (null!=sb && sb.length() > 0) {
                url = new URL(reqUrl + "?" + sb.substring(0, sb.length() - 1));
            } else {
                url = new URL(reqUrl);
            }
        } catch (MalformedURLException e) {
            logger.info("MalformedURLException",e);
            return null ;
        }
        return url.toString();
    }

    /**
     * 发起https请求并获取结果
     * @param requestUrl 请求地址
     * @param requestMethod 请求方式（GET、POST）
     * @return JSONObject(通过JSONObject.get(key)的方式获取json对象的属性值)
     */
    public String httpRequest(String requestUrl, String requestMethod) {
        StringBuffer buffer = new StringBuffer();
        try {
            // 创建SSLContext对象，并使用我们指定的信任管理器初始化
            TrustManager[] tm = { new MyX509TrustManager() };
            SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
            sslContext.init(null, tm, new java.security.SecureRandom());

            // 从上述SSLContext对象中得到SSLSocketFactory对象
            SSLSocketFactory ssf = sslContext.getSocketFactory();

            //打开连接
            URL url = new URL(requestUrl);
            HttpsURLConnection httpUrlConn = (HttpsURLConnection) url.openConnection();
            httpUrlConn.setSSLSocketFactory(ssf);
            httpUrlConn.setDoOutput(true);
            httpUrlConn.setDoInput(true);
            httpUrlConn.setUseCaches(false);

            // 设置请求方式（GET/POST）
            httpUrlConn.setRequestMethod(requestMethod);

            if ("GET".equalsIgnoreCase(requestMethod)){
                httpUrlConn.connect();
            }
            // 将返回的输入流转换成字符串
            InputStream inputStream = httpUrlConn.getInputStream();
            InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
            BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
            String str;
            while ((str = bufferedReader.readLine()) != null) {
                buffer.append(str);
            }
            bufferedReader.close();
            inputStreamReader.close();
            // 释放资源
            inputStream.close();
            httpUrlConn.disconnect();
        } catch (ConnectException ce) {
            logger.error(" server connection timed out."+ce);
        } catch (Exception e) {
            logger.error("https request error:{}", e);
        }
        return buffer.toString();
    }
}
